/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  intl.c
 *         \unit  intl
 *        \brief  This is a simple large inter number calculate module for C language
 *       \author  Lamdonn
 *      \version  v1.1.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#include "intl.h"

/* Internal static function declarations */

static int intl_ucmp(intl a, intl b);
static intl intl_umul(intl a, intl b);
static intl intl_udiv(intl a, intl b, intl *mod);
static intl intl_umod(intl a, intl b);

/** 
 * \brief Adds two intl numbers.
 * 
 * This function computes the sum of two intl.
 * It processes each 16-bit part of the input integers, 
 * handling carry bits as necessary. The result is stored in a 
 * new intl number. This function ensures that overflow is 
 * correctly managed across all parts.
 * 
 * \param[in] a: The first operand (intl number).
 * \param[in] b: The second operand (intl number).
 * \return The sum of a and b as an intl.
 */
intl intl_add(intl a, intl b) 
{
    intl result; // Initialize the result variable
    uint16_t carry = 0; /** Carry bit */

    // Perform addition for each 16-bit part
    for (int i = 0; i < __INTL_U16_PARTS__; i++) 
    {
        // Calculate the sum of corresponding parts and carry
        uint32_t sum = (uint32_t)a.u16[i] + (uint32_t)b.u16[i] + carry;
        result.u16[i] = (uint16_t)(sum & 0xFFFF); /** Lower 16 bits */
        carry = (sum >> 16) & 0xFFFF; /** Upper 16 bits as carry */
    }

    return result; // Return the resulting intl number
}

/** 
 * \brief Subtracts one intl number from another.
 * 
 * This function computes the difference of two intl.
 * It processes each 16-bit part of the minuend and 
 * subtrahend, handling borrow bits as necessary. The result is 
 * stored in a new intl number. This function ensures that 
 * borrowing is correctly managed across all parts.
 * 
 * \param[in] a: The minuend (the number from which another is to be subtracted).
 * \param[in] b: The subtrahend (the number to be subtracted).
 * \return The result of a - b as an intl.
 */
intl intl_sub(intl a, intl b) 
{
    intl result; // Initialize the result variable

    // Perform subtraction for each 16-bit part
    for (int i = 0; i < __INTL_U16_PARTS__; i++) 
    {
        uint32_t diff = (uint32_t)a.u16[i] - (uint32_t)b.u16[i];
        
        // Check if a borrow occurred
        if (diff & 0xFFFF0000) /** Borrow occurred */
        {
            // Adjust the higher parts to account for the borrow
            for (int j = i + 1; j < __INTL_U16_PARTS__; j++) 
            {
                a.u16[j] -= 1; // Borrow from the next part
                if (a.u16[j] != 0xFFFF) break; // Stop if no further borrow needed
            }
        }
        
        // Store the result of the subtraction
        result.u16[i] = (uint16_t)(diff & 0xFFFF);
    }

    return result; // Return the resulting intl number
}

/** 
 * \brief Increments the intl number by one.
 * 
 * This function increments a intl by one. 
 * It processes each 32-bit part of the input integer and 
 * handles carry bits as necessary. The function continues 
 * to increment the subsequent parts until there is no overflow.
 * 
 * \param[in] a: The intl number to increment.
 * \return The incremented intl number as an intl.
 */
intl intl_inc(intl a) 
{
    // Increment each 32-bit part of the intl number
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        a.u32[i]++; // Increment the current part
        // Check if the current part overflowed
        if (a.u32[i] != 0) 
        {
            break; /** Return immediately if no overflow */
        }
    }
    return a; /** Return the incremented result */
}

/** 
 * \brief Decrements the intl number by one.
 * 
 * This function decrements a intl by one. 
 * It processes each 32-bit part of the input integer, handling 
 * borrowing as necessary. If the current part is zero, it sets 
 * that part to its maximum value (0xFFFFFFFF) and continues 
 * to the next part to borrow from it.
 * 
 * \param[in] a: The intl number to decrement.
 * \return The decremented intl number as an intl.
 */
intl intl_dec(intl a) 
{
    // Decrement each 32-bit part of the intl number
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        // Check if the current part can be decremented
        if (a.u32[i] != 0) 
        {
            a.u32[i]--; // Decrement the current part
            break; /** Return immediately if current part can be decremented */
        }
        // If current part is zero, set it to max value and continue borrowing
        a.u32[i] = 0xFFFFFFFF; 
    }
    return a; /** Return the decremented result */
}

/** 
 * \brief Multiplies two intl unsigned numbers.
 * 
 * This function performs multiplication of two intl
 * by using a method similar to the schoolbook algorithm. The 
 * multiplication is carried out by breaking the numbers into their 
 * 16-bit components and accumulating the results. The function handles 
 * carry-over during the multiplication and addition stages to ensure 
 * the final product is accurately represented.
 * 
 * \param[in] a: The first operand to multiply.
 * \param[in] b: The second operand to multiply.
 * \return The product of a and b as an intl.
 */
static intl intl_umul(intl a, intl b) 
{
    intl result = __INTL_ZERO__; /** Initialize the result to 0 */
    intl temp[__INTL_U16_PARTS__] = {{0}}; // Temporary storage for intermediate results
    uint16_t carry = 0; // Variable to hold carry-over during multiplication

    // Perform multiplication
    for (int i = 0; i < __INTL_U16_PARTS__; i++) 
    {
        carry = 0; // Reset carry for the current row
        for (int j = 0; j < __INTL_U16_PARTS__; j++) 
        {
            if (i + j < __INTL_U16_PARTS__) 
            {
                // Multiply the 16-bit segments and add carry
                uint32_t mul = (uint32_t)a.u16[i] * (uint32_t)b.u16[j] + carry;
                temp[i].u16[i + j] = (mul & 0xFFFF); // Store the lower 16 bits
                carry = ((mul >> 16) & 0xFFFF); // Update carry for the next addition
            }
        }
    }

    carry = 0; // Reset carry for the addition phase
    // Combine results from the temporary storage
    for (int i = 0; i < __INTL_U16_PARTS__; i++) 
    {
        uint32_t add = 0; // Variable to hold the sum of the current column
        for (int j = 0; j < __INTL_U16_PARTS__; j++) 
        {
            add += temp[j].u16[i]; // Accumulate results from temp
        }
        add += carry; // Add any carry from the previous column
        result.u16[i] = (add & 0xFFFF); // Store the lower 16 bits in result
        carry = ((add >> 16) & 0xFFFF); // Update carry for the next column
    }

    return result; // Return the final product
}

/** 
 * \brief Multiplies two intl numbers.
 * 
 * This function multiplies two intl and returns 
 * the product as another intl number. It handles signed multiplication 
 * by checking the sign of the operands. If either operand is negative, 
 * it negates the operand and adjusts the sign of the result accordingly. 
 * The actual multiplication is performed using the `intl_umul` 
 * function, which handles the absolute values of the integers.
 * 
 * \param[in] a: The first operand to multiply.
 * \param[in] b: The second operand to multiply.
 * \return The product of a and b as an intl.
 */
intl intl_mul(intl a, intl b)
{
    intl result = __INTL_ZERO__; // Initialize the result to 0
    int sign = 1; // Variable to track the sign of the result

    // Check and handle the sign of the first operand
    if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000)
    {
        sign = -sign; // Negate the sign for the result
        a = intl_neg(a); // Negate the first operand
    }

    // Check and handle the sign of the second operand
    if (b.u32[__INTL_U32_PARTS__ - 1] & 0x80000000)
    {
        sign = -sign; // Negate the sign for the result
        b = intl_neg(b); // Negate the second operand
    }

    // Perform unsigned multiplication
    result = intl_umul(a, b);
    
    // If the result should be negative, negate it
    if (sign < 0) 
        result = intl_neg(result);
    
    return result; // Return the final product
}

/** 
 * \brief Divides one intl unsigned number by another.
 * 
 * This function performs division of one intl 
 * by another. It calculates the quotient using a bitwise approach, 
 * handling division by zero gracefully. The result is built bit by bit 
 * from the most significant bit to the least significant bit. If the 
 * divisor is zero, it prints an error message and returns zero.
 * 
 * \param[in] a: The dividend (number to be divided).
 * \param[in] b: The divisor (number to divide by).
 * \return The quotient of a divided by b as an intl.
 */
static intl intl_udiv(intl a, intl b, intl *mod)  
{
    // Check for division by zero
    if (intl_sign(b) == 0) { INTL_E(INTL_E_DIV_0, '0'); return __INTL_ZERO__; }

    intl result = __INTL_ZERO__;      // Initialize the result to zero
    intl remainder = __INTL_ZERO__;   // Initialize the remainder to zero

    /** Calculate bit by bit from the highest bit */
    for (int i = __INTL_BIT_PARTS__ - 1; i >= 0; i--) 
    {
        /** Left shift remainder and add current bit */
        remainder = intl_shl(remainder, 1); // Shift remainder left by 1
        remainder.u32[0] |= (a.u32[i / 32] >> (i % 32)) & 1; // Add current bit from dividend

        /** If remainder is greater than or equal to b, subtract b */
        if (intl_ucmp(remainder, b) >= 0) 
        {
            remainder = intl_sub(remainder, b); // Subtract b from remainder
            result.u32[i / 32] |= (1 << (i % 32)); // Set corresponding bit in result
        }
    }

    if (mod) *mod = remainder;

    return result; // Return the final quotient
}

/** 
 * \brief Divides one intl number by another.
 * 
 * This function performs division of two intl 
 * and returns the quotient as another intl number. It handles signed 
 * division by checking the sign of the operands. If either operand 
 * is negative, it negates the operand and adjusts the sign of the 
 * result accordingly. The actual division is performed using the 
 * `intl_udiv` function, which handles the absolute values of 
 * the integers.
 * 
 * \param[in] a: The dividend (number to be divided).
 * \param[in] b: The divisor (number to divide by).
 * \return The quotient of a divided by b as an intl.
 */
intl intl_div(intl a, intl b)
{
    intl result = __INTL_ZERO__; // Initialize the result to 0
    int sign = 1; // Variable to track the sign of the result

    // Check and handle the sign of the dividend
    if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000)
    {
        sign = -sign; // Negate the sign for the result
        a = intl_neg(a); // Negate the dividend
    }

    // Check and handle the sign of the divisor
    if (b.u32[__INTL_U32_PARTS__ - 1] & 0x80000000)
    {
        sign = -sign; // Negate the sign for the result
        b = intl_neg(b); // Negate the divisor
    }

    // Perform unsigned division
    result = intl_udiv(a, b, NULL);

    // If the result should be negative, negate it
    if (sign < 0) 
        result = intl_neg(result);
    
    return result; // Return the final quotient
}

/** 
 * \brief Computes the remainder of the division of two unsigned intl numbers.
 * 
 * This function calculates the remainder of the division of two 
 * intl. It uses a bitwise approach to 
 * compute the remainder by processing each bit from the most significant 
 * to the least significant. If the divisor is zero, it handles the 
 * error gracefully by printing a message and returning zero.
 * 
 * \param[in] a: The dividend (number to be divided).
 * \param[in] b: The divisor (number to divide by).
 * \return The remainder of a divided by b as an intl.
 */
static intl intl_umod(intl a, intl b) 
{
    intl mod = __INTL_ZERO__;
    intl_udiv(a, b, &mod);
    return mod;
}

/** 
 * \brief Computes the remainder of the division of two intl numbers.
 * 
 * This function calculates the remainder of the division of two 
 * intl. It handles signed integers by checking 
 * the sign of the dividend. If the dividend is negative, it negates 
 * the dividend before performing the unsigned modulus operation. 
 * The sign of the result is adjusted based on the sign of the 
 * dividend. The actual remainder calculation is performed using the 
 * `intl_umod` function, which handles the absolute values of 
 * the integers.
 * 
 * \param[in] a: The dividend (number to be divided).
 * \param[in] b: The divisor (number to divide by).
 * \return The remainder of a divided by b as an intl.
 */
intl intl_mod(intl a, intl b)
{
    intl result = __INTL_ZERO__; // Initialize result to zero
    int sign = 1; // Variable to track the sign of the result

    // Check and handle the sign of the dividend
    if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000)
    {
        sign = -sign; // Negate the sign for the result
        a = intl_neg(a); // Negate the dividend
    }

    // Perform unsigned modulus with the absolute value of the divisor
    result = intl_umod(a, intl_abs(b));

    // If the result should be negative, negate it
    if (sign < 0) 
        result = intl_neg(result);
    
    return result; // Return the final remainder
}

/** 
 * \brief Left shifts an intl number by a specified number of bits.
 * 
 * This function performs a left bitwise shift on a intl. 
 * The shift b can be greater than 32 bits, in which case 
 * the function calculates how many whole 32-bit parts to shift and 
 * how many bits to shift within the remaining part. It constructs 
 * the result based on the input number after applying the shift.
 * 
 * \param[in] a: The intl number to shift.
 * \param[in] b: The number of bits to shift to the left.
 * \return The left-shifted intl number.
 */
intl intl_shl(intl a, uint32_t b) 
{
    intl result = __INTL_ZERO__; // Initialize the result to zero
    int u32bias = b / 32; // Number of whole 32-bit parts to shift
    int bitsbias = b % 32; // Remaining bits to shift

    // Perform the shift for each 32-bit part of the intl number
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        if (i < u32bias)
        {
            result.u32[i] = 0; // Set shifted-out parts to zero
        }
        else 
        {
            // Shift the current part and add bits from the previous part if needed
            result.u32[i] = (a.u32[i - u32bias] << bitsbias) | 
                (((i - u32bias - 1) >= 0 && bitsbias > 0) ? 
                (a.u32[i - u32bias - 1] >> (32 - bitsbias)) : 0);
        }
    }
    return result; // Return the left-shifted result
}

/** 
 * \brief Right shifts an intl number by a specified number of bits.
 * 
 * This function performs a right bitwise shift on a intl. 
 * The shift b can be greater than 32 bits, in which case 
 * the function calculates how many whole 32-bit parts to shift and 
 * how many bits to shift within the remaining part. It constructs 
 * the result based on the input number after applying the shift. 
 * The sign bit is preserved for signed shifts.
 * 
 * \param[in] a: The intl number to shift.
 * \param[in] b: The number of bits to shift to the right.
 * \return The right-shifted intl number.
 */
intl intl_shr(intl a, uint32_t b) 
{
    intl result = __INTL_ZERO__; // Initialize the result to zero
    int u32bias = b / 32; // Number of whole 32-bit parts to shift
    int bitsbias = b % 32; // Remaining bits to shift

    // Perform the shift for each 32-bit part of the intl number
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        // Check if the current index is beyond the range for valid shifts
        if (i > __INTL_U32_PARTS__ - u32bias - 1 && __INTL_U32_PARTS__ - u32bias - 1 >= 0)
        {
            result.u32[i] = 0; // Set shifted-out parts to zero
        }
        else 
        {
            // Shift the current part and add bits from the next part if needed
            result.u32[i] = (a.u32[i + u32bias] >> bitsbias) | 
                (((i + u32bias + 1) < __INTL_U32_PARTS__ && bitsbias > 0) ? 
                (a.u32[i + u32bias + 1] << (32 - bitsbias)) : 
                ((a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) ? 0xFFFFFFFF : 0));
        }
    }

    return result; // Return the right-shifted result
}

/** 
 * \brief Performs bitwise AND operation on two intl numbers.
 * 
 * This function computes the bitwise AND of two intl.
 * It processes each 32-bit part of the input integers and 
 * performs the AND operation on corresponding parts, storing the 
 * result in a new intl number. This operation yields a number that 
 * has bits set only where both operands have bits set.
 * 
 * \param[in] a: The first operand (intl number).
 * \param[in] b: The second operand (intl number).
 * \return The result of a AND b as an intl.
 */
intl intl_and(intl a, intl b) 
{
    intl result; // Initialize the result variable
    // Perform the bitwise AND operation for each 32-bit part
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        result.u32[i] = a.u32[i] & b.u32[i]; // Compute AND for each part
    }
    return result; // Return the resulting intl number
}

/** 
 * \brief Performs bitwise OR operation on two intl numbers.
 * 
 * This function computes the bitwise OR of two intl.
 * It processes each 32-bit part of the input integers and 
 * performs the OR operation on corresponding parts, storing the 
 * result in a new intl number. This operation yields a number that 
 * has bits set where at least one of the operands has bits set.
 * 
 * \param[in] a: The first operand (intl number).
 * \param[in] b: The second operand (intl number).
 * \return The result of a OR b as an intl.
 */
intl intl_or(intl a, intl b) 
{
    intl result; // Initialize the result variable
    // Perform the bitwise OR operation for each 32-bit part
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        result.u32[i] = a.u32[i] | b.u32[i]; // Compute OR for each part
    }
    return result; // Return the resulting intl number
}

/** 
 * \brief Performs bitwise XOR operation on two intl numbers.
 * 
 * This function computes the bitwise XOR of two intl.
 * It processes each 32-bit part of the input integers and 
 * performs the XOR operation on corresponding parts, storing the 
 * result in a new intl number. This operation yields a number that 
 * has bits set where only one of the operands has bits set.
 * 
 * \param[in] a: The first operand (intl number).
 * \param[in] b: The second operand (intl number).
 * \return The result of a XOR b as an intl.
 */
intl intl_xor(intl a, intl b) 
{
    intl result; // Initialize the result variable
    // Perform the bitwise XOR operation for each 32-bit part
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        result.u32[i] = a.u32[i] ^ b.u32[i]; // Compute XOR for each part
    }
    return result; // Return the resulting intl number
}

/** 
 * \brief Performs bitwise NOT operation on an intl number.
 * 
 * This function computes the bitwise NOT (negation) of a intl.
 * It processes each 32-bit part of the input integer 
 * and applies the NOT operation, storing the result in a new intl 
 * number. This operation inverts all bits of the input number.
 * 
 * \param[in] a: The intl number to negate.
 * \return The bitwise negation of a as an intl.
 */
intl intl_not(intl a) 
{
    intl result; // Initialize the result variable
    // Perform the bitwise NOT operation for each 32-bit part
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        result.u32[i] = ~a.u32[i]; // Compute NOT for each part
    }
    return result; // Return the resulting intl number
}

/** 
 * \brief Computes the absolute value of an intl number.
 * 
 * This function checks if the given intl 
 * represents a negative value in two's complement representation. 
 * If the most significant bit (sign bit) of the highest 32-bit segment 
 * is set, it indicates a negative number, and the function calls 
 * intl_neg to return its positive equivalent. If the number is 
 * already non-negative, it simply returns the original number.
 * 
 * \param[in] a: The intl number for which to compute the absolute value.
 * \return The absolute value of the intl number a.
 */
intl intl_abs(intl a) 
{
    // Check if the sign bit of the highest 32-bit part is set
    if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) 
        return intl_neg(a); // Return negated value if negative
    return a; // Return the original value if non-negative
}

/** 
 * \brief Converts a string to an intl number.
 * 
 * This function converts a string representation of a number 
 * in various bases (decimal, binary, octal, hexadecimal) 
 * into a intl. It handles optional signs 
 * and base prefixes, and processes the string from the end to 
 * the start for efficiency in base conversions.
 * 
 * \param[in] str: The string to convert.
 * \return The converted intl number. Returns zero if the 
 *         string is invalid or represents zero.
 */
intl intl_from(const char *str) 
{
    const uint8_t ttable[4] = {10, 2, 8, 16}; // Table of digit limits for each base
    const uint8_t btable[4] = {0, 1, 3, 4};   // Table of bit shifts for each base
    uint32_t type = 0; // 0 - decimal, 1 - binary, 2 - octal, 3 - hexadecimal
    intl result = __INTL_ZERO__; // Resulting intl number
    intl base = intl(1); /** Base initialized to 1 */
    int sign = 1; // Sign of the number (1 for positive, -1 for negative)
    const char *p = str; // Pointer to traverse the input string

    // Determine the number type based on the string prefix
    switch (*p)
    {
    case '0': {
        if (p[1] == 0) { return __INTL_ZERO__; } // Handle case of "0"
        else if (p[1] == 'x' || p[1] == 'X') type = 3; // Hexadecimal
        else if (p[1] == 'o' || p[1] == 'O') type = 2; // Octal
        else if (p[1] == 'b' || p[1] == 'B') type = 1; // Binary
        else if (p[1] < '0' || p[1] > '9') { INTL_E(INTL_E_INVALID_CAHRACTER, p[1]); return __INTL_ZERO__; }
        p += 2; // Move past the prefix
    } break;
    case '-': { sign = -1; } // Handle negative sign
    case '+': { p++; } break; // Handle positive sign
    default:
        break; // No sign or prefix
    }

    uint32_t len = strlen(p); // Length of the number string
    const char *s = &p[len - 1]; // Pointer to the last character of the number string

    // Process decimal numbers
    if (type == 0)
    {
        while (s >= p) // Traverse the string backwards
        {
            char c = *s;

            /** Check if the character is a digit */
            if (c < '0' || c > '9') { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; }

            uint32_t num = c - '0'; /** Convert character to number */

            /** Process current digit */
            intl addend = intl_umul(base, (intl){num}); // Multiply base by the digit
            result = intl_add(result, addend); // Add to result

            /** Multiply base by 10 for the next digit */
            base = intl_umul(base, (intl){10});

            s--; // Move to the previous character
        }

        // Apply sign if negative
        if (sign == -1) result = intl_neg(result);
    }
    else  
    {
        // Process non-decimal bases (binary, octal, hexadecimal)
        uint8_t bit = 0; // Bit position within the current u32 part
        int index = 0; // Current index in the result array
        while (s >= p && index < __INTL_U32_PARTS__)
        {
            char c = *s;

            if      (c >= '0' && c <= '9') c -= '0';
            else if (c >= 'A' && c <= 'F') c -= 55; // c = c - 'A' + 10 // 55
            else if (c >= 'a' && c <= 'f') c -= 87; // c = c - 'a' + 10 // 87
            else { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; }

            if (c >= ttable[type]) { INTL_E(INTL_E_INVALID_CAHRACTER, *s); return __INTL_ZERO__; }

            result.u32[index] |= (c << bit); // Set the value in the corresponding bit
            if ((type == 2) && (bit > 29) && (index < __INTL_U32_PARTS__ - 1)) // For oct, stitching to high u32 is required, 2,1,0,31,30,29
            {
                result.u32[index + 1] |= (c >> (32 - bit));
            }
            bit += btable[type]; // Update the bit position
            if (bit >= 32) // If bit exceeds 32, move to the next part
            {
                bit -= 32; // Reset bit position
                index++; // Move to the next u32 part
            }
            
            s--; // Move to the previous character
        }
    }

    return result; // Return the resulting intl number
}

/** 
 * \brief Converts a 32-bit unsigned integer to an intl number.
 * 
 * This function initializes the first 32-bit segment of the intl structure 
 * with the provided 32-bit unsigned integer value, while the other segments 
 * are set to zero. This allows for easy conversion from a standard integer type 
 * to the custom muti-bit representation.
 * 
 * \param[in] value: The 32-bit unsigned integer to convert.
 * \return The corresponding intl number initialized with the given value.
 */
intl intl_from2(int value)
{
    intl result = __INTL_ZERO__;
    memcpy(&result, &value, sizeof(value));
    if (value < 0) 
    {
        memset(((char *)(&result)) + sizeof(value), -1, sizeof(result) - sizeof(value));
    }
    return result;
}

/** 
 * \brief Determines the sign of an intl number.
 * 
 * This function checks the sign of the given intl
 * based on its representation. It first examines the most significant 
 * bit of the highest 32-bit segment to determine if the number is negative. 
 * If this bit is set, the function returns -1, indicating a negative value. 
 * If all segments are zero, it returns 0, indicating that the number is zero. 
 * If the number is positive, it returns 1.
 * 
 * \param[in] a: The intl number to evaluate for its sign.
 * \return -1 if the number is negative, 0 if the number is zero, and 
 *         1 if the number is positive.
 */
int intl_sign(intl a)
{
    // Check if the sign bit of the highest 32-bit part is set
    if (a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) return -1;

    // Check if the number is zero
    for (int i = __INTL_U32_PARTS__ - 1; i >= 0; i--) 
    {
        if (a.u32[i] != 0) return 1; // Return 1 if any part is non-zero
    }
    
    return 0; // Return 0 if all parts are zero
}

#define FLAGS_ZEROPAD                       (0x01)
#define FLAGS_LEFT                          (0x02)
#define FLAGS_PLUS                          (0x04)
#define FLAGS_SPACE                         (0x08)
#define FLAGS_HASH                          (0x10)
#define PRINT_CHAR(c)                       do { if (length < max) { buffer[length++] = (c); } else return -2; } while (0)

/** 
 * \brief Converts an intl number to a string.
 * 
 * This function converts a given intl into a string representation. 
 * Including dec, bin, oct, hex string.
 * 
 * \param[in] a: The intl number to convert.
 * \param[out] buffer: The buffer to store the resulting string.
 *                     It should be large enough to hold the representation.
 * \param[in] size: The size of buffer, can refer to `INTL_PRINT_MAX`.
 * \param[in] format: Printf-like format, [flags][width][type].
 *                      flags: '0' '-' '+' ' ' '#'
 *                      width: dec numeber
 *                      type: 'x' 'X' 'o' 'O' 'b' 'B' 'd' 'i' 'u' 
 * \return The length of the string that was converted successfully.
 *              0: Invalid convertion
 *              -1: Null pointer `buffer`
 *              -2: `size` is too small
 *              -3: Null pointer `format`
 */
int intl_print(intl a, char *buffer, uint32_t size, const char *format)
{
    const uint8_t btable[4] = {0, 1, 3, 4};   // Table of bit shifts for each base
    uint32_t type = 0; // 0 - decimal, 1 - binary, 2 - octal, 3 - hexadecimal
    int length = 0;
    int i = 0, j = 0;
    uint32_t flags = 0, width = 0;
    uint32_t max = size - 1;
    char c = 0;
    char prefix[2] = {0, 0};
    char prelen = 0;

    if (!buffer) return -1;
    if (size < 2) return -2;
    if (!format) return -3;

    for (; *format; format++)
    {
        if (length > 0) break;

        while (1)
        {
            if      (*format == '0') { flags |= FLAGS_ZEROPAD; format++; }
            else if (*format == '-') { flags |= FLAGS_LEFT;    format++; }
            else if (*format == '+') { flags |= FLAGS_PLUS;    format++; }
            else if (*format == ' ') { flags |= FLAGS_SPACE;   format++; }
            else if (*format == '#') { flags |= FLAGS_HASH;    format++; }
            else break;
        }

        /* Convert width */
        while ((*format >= '0') && (*format <= '9')) width = width * 10U + (unsigned int)(*format++ - '0');
        if (width > max) return -1;

        /* format distribution */
        switch (*format)
        {
        case 'X':
        case 'x': type++;
        case 'O':
        case 'o': type++;
        case 'B':
        case 'b': type++;
        {
            int valid = 0;
            int u32part = 0;
            int u32bias = 0;

            if (flags & FLAGS_HASH)
            {
                prefix[prelen++] = '0';
                prefix[prelen++] = *format;
            }

            if (intl_eq(a, __INTL_ZERO__)) PRINT_CHAR('0');
            else 
            {
                for (valid = __INTL_U32_PARTS__ - 1; valid >= 0; valid--)
                {
                    if (a.u32[valid] != 0) break;
                }

                while (u32part <= valid)
                {
                    c = (a.u32[u32part] >> u32bias) & ((1 << btable[type]) - 1);

                    /* For hexadecimal, convert the letters */
                    if (c >= 10) c += (*format == 'x' ? 39 : 7);

                    /* The bits of the previous part need to be concatenated to form octal */
                    if (type == 2 && u32part < valid && u32bias > 29) c |= ((a.u32[u32part + 1] << (32 - u32bias)) & 0x7);
                
                    PRINT_CHAR(c + '0');

                    /* Update the u32 index of the current transition and the bit bias */
                    u32bias += btable[type];
                    if (u32bias >= 32)
                    {
                        u32part++;
                        u32bias %= 32;
                    }

                    /* If there are no valid bits left, the conversion is exited */
                    if ((u32part == valid) && ((a.u32[u32part] >> u32bias) == 0)) break;
                }
            }
        } break;
        case 'u':
        case 'd':
        case 'i': 
        {
            intl ten = intl(10); /** Base 10 for conversion */
            intl remainder; // To hold the remainder during division
            intl temp = a; // Temporary variable for manipulation

            if (intl_eq(a, __INTL_ZERO__)) PRINT_CHAR('0');
            else  
            {
                // Check if the number is negative
                if (*format != 'u' && a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) temp = intl_neg(a); // Negate the number for conversion

                /** Calculate decimal string of intl */
                while (intl_ucmp(temp, __INTL_ZERO__) > 0) // While the number is positive
                {
                    temp = intl_udiv(temp, ten, &remainder); // Get remainder when divided by 10, and update temp
                    PRINT_CHAR('0' + remainder.u32[0]); // Convert remainder to character, store character in buffer
                }

                // If the original number was negative, add '-' sign
                if (*format != 'u' && a.u32[__INTL_U32_PARTS__ - 1] & 0x80000000) prefix[prelen++] = '-'; // Append negative sign
                else  
                {
                    if (flags & FLAGS_PLUS) prefix[prelen++] = '+';
                }
            }
        } break;
        default:
            return 0;
        }
    }

    /* Right align */
    if (!((flags & FLAGS_LEFT)) && (flags & FLAGS_ZEROPAD)) while (length + prelen < width) PRINT_CHAR('0');
    while (prelen > 0) PRINT_CHAR(prefix[--prelen]);
    if (!((flags & FLAGS_LEFT)) && !(flags & FLAGS_ZEROPAD)) while (length < width) PRINT_CHAR(' ');
    
    /* Reverse */
    for (i = 0, j = length - 1; i < j; i++, j--)
    {
        c = buffer[i]; // Temporary variable for swapping
        buffer[i] = buffer[j]; // Swap start and end
        buffer[j] = c;
    }

    /* Left align */
    if (flags & FLAGS_LEFT) while (length < width) PRINT_CHAR(' ');

    buffer[length] = 0;

    return length;
}

/** 
 * \brief Compares two intl unsigned numbers.
 * 
 * This function compares two intl 
 * by examining each 32-bit segment from the most significant to 
 * the least significant. It returns 1 if the first number is 
 * greater than the second, -1 if it is less, and 0 if they are 
 * equal. The comparison is done in a way that respects the 
 * unsigned nature of the integers.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * \return 1 if a > b, -1 if a < b, and 0 if a == b.
 */
static int intl_ucmp(intl a, intl b) 
{
    // Compare each 32-bit part from the most significant to the least significant
    for (int i = __INTL_U32_PARTS__ - 1; i >= 0; i--) 
    {
        if (a.u32[i] > b.u32[i]) return 1;  // a is greater
        if (a.u32[i] < b.u32[i]) return -1; // a is less
    }
    return 0; // a and b are equal
}

/** 
 * \brief Compares two intl numbers.
 * 
 * This function compares two intl and 
 * determines their relative order. The comparison is performed 
 * starting from the most significant part (highest order) to 
 * the least significant part (lowest order).
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return 1 if a > b, -1 if a < b, 0 if a == b.
 */
static int intl_cmp(intl a, intl b) 
{
    // Compare each 32-bit part from the most significant to the least significant
    for (int i = __INTL_U32_PARTS__ - 1; i >= 0; i--) 
    {
        // Compare the current parts as signed integers
        if ((int32_t)a.u32[i] > (int32_t)b.u32[i]) return 1; // a is greater
        if ((int32_t)a.u32[i] < (int32_t)b.u32[i]) return -1; // a is less
    }
    return 0; // a is equal to b
}

/** 
 * \brief Compares two intl numbers, determine whether a < b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a < b ?
 */
int intl_lt(intl a, intl b)
{
    return intl_cmp(a, b) < 0 ? 1 : 0;
}

/** 
 * \brief Compares two intl numbers, determine whether a <= b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a <= b ?
 */
int intl_le(intl a, intl b)
{
    return intl_cmp(a, b) <= 0 ? 1 : 0;
}

/** 
 * \brief Compares two intl numbers, determine whether a == b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a == b ?
 */
int intl_eq(intl a, intl b)
{
    return intl_cmp(a, b) == 0 ? 1 : 0;
}

/** 
 * \brief Compares two intl numbers, determine whether a != b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a != b ?
 */
int intl_ne(intl a, intl b)
{
    return intl_cmp(a, b) != 0 ? 1 : 0;
}

/** 
 * \brief Compares two intl numbers, determine whether a > b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a > b ?
 */
int intl_gt(intl a, intl b)
{
    return intl_cmp(a, b) > 0 ? 1 : 0;
}

/** 
 * \brief Compares two intl numbers, determine whether a >= b.
 * 
 * \param[in] a: The first number to compare.
 * \param[in] b: The second number to compare.
 * 
 * \return a >= b ?
 */
int intl_ge(intl a, intl b)
{
    return intl_cmp(a, b) >= 0 ? 1 : 0;
}

/** 
 * \brief Computes the two's complement (negation) of an intl number.
 * 
 * This function calculates the negative representation of a given intl
 * using two's complement. It first inverts all bits 
 * of the input number and then adds one to the result. This effectively 
 * represents the negative value of the original number in a signed 
 * integer format.
 * 
 * \param[in] a: The intl number to negate.
 * \return The negated intl number (two's complement of a).
 */
intl intl_neg(intl a)
{
    intl result = __INTL_ZERO__;

    // First, bitwise NOT (invert) the input number
    for (int i = 0; i < __INTL_U32_PARTS__; i++) 
    {
        result.u32[i] = ~a.u32[i];
    }

    // Add one to complete the two's complement operation
    return intl_inc(result);
}

